/**
 * @author Francesco di Dio
 * Date: 20/apr/2013
 * Titolo: JKSimpleController.java
 * Versione: 
 */

/**
 * Copyright (c) 2013 Francesco di Dio.
 * tabuto83@gmail.com 
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
package com.tabuto.jkeys.controllers;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

import org.apache.log4j.Logger;

import com.tabuto.jkeys.JKUtils;
import com.tabuto.jkeys.JKeysConstant;
import com.tabuto.jkeys.Preferences;
import com.tabuto.jkeys.models.AbstractJKeyModel;
import com.tabuto.jkeys.models.Account;
import com.tabuto.jkeys.models.AccountGroup;
import com.tabuto.jkeys.models.AccountGroupList;
import com.tabuto.jkeys.views.JKViewInterface;


public final class JKSimpleController implements JKControllerInterface {
	
	private static final Logger log = Logger.getLogger(JKSimpleController.class);

	private AccountGroupList root = new AccountGroupList();
	private AbstractJKeyModel selected = Account.NEW_EMPTY_ACCOUNT();
	private String password = null;

	private JKViewInterface view = null;

	
	public JKSimpleController(){}
	
//	public JKSimpleController(JKViewInterface mainWindow) {
//	
//	}

	@Override
	public AbstractJKAction getNewAccountAction() {
		
		return new AbstractJKAction("getNewAccountAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 2837192650800066618L;

			@Override
			protected void doAction(ActionEvent e) {
				select(Account.NEW_EMPTY_ACCOUNT());
				view.refresh();

			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tabuto.jkeys.controllers.JKControllerInterface#getShowPasswordAction
	 * ()
	 */
	@Override
	public AbstractJKAction getShowPasswordAction() {
		// TODO Auto-generated method stub
		return new AbstractJKAction("getShowPasswordAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 4169409835563436491L;

			@Override
			protected void doAction(ActionEvent e) {
				
				view.switchShowPasswordMode();
				view.refreshDetail();
			}
		};
	}

	@Override
	public AccountGroup getRoot() {
		return root;
	}

	@Override
	public AbstractJKAction getSelectAccountAction() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public AbstractJKeyModel getSelectedAccount() {
		return (selected==null?Account.NEW_EMPTY_ACCOUNT():selected);
	}

	private void select(AbstractJKeyModel toSelect) {
		this.selected = toSelect;
	}

	private void setRoot(AccountGroupList root) {
		this.root = root;
	}

	@Override
	public MouseAdapter getTreeAccountsMouseAdapter(JTree treeJList) {
		log.info("Call getTreeAccountsMouseAdapter");
		return new MouseAdapter() {

			public void mouseClicked(MouseEvent mouseEvent) {

				log.debug("Mouse Clicked on JTree");
				JTree tree = (JTree) mouseEvent.getSource();
				TreePath[] nodes = tree.getSelectionPaths();
				TreePath treePath = null;
				DefaultMutableTreeNode node = null;

				if (nodes == null)
					return;

				if (nodes.length == 1) {
					treePath = nodes[0];

					node = (DefaultMutableTreeNode) treePath
							.getLastPathComponent();
					if (node.getUserObject() != null
							&& node.getUserObject() instanceof AbstractJKeyModel) {
						select((AbstractJKeyModel) node.getUserObject());
						view.refreshDetail();
					}
				}

			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tabuto.jkeys.controllers.JKControllerInterface#getCopyPasswordAction
	 * ()
	 */
	@Override
	public AbstractJKAction getCopyPasswordAction() {

		return new AbstractJKAction("getCopyPasswordAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 7657491801846475761L;

			@Override
			protected void doAction(ActionEvent e) {
				if (getSelectedAccount() != null
						&& getSelectedAccount() instanceof Account) {
					Toolkit toolkit = Toolkit.getDefaultToolkit();
					Clipboard clipboard = toolkit.getSystemClipboard();
					StringSelection strSel = new StringSelection(
							((Account) getSelectedAccount()).getPassword());
					clipboard.setContents(strSel, null);
				}

			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tabuto.jkeys.controllers.JKControllerInterface#getCopyUsernameAction
	 * ()
	 */
	@Override
	public AbstractJKAction getCopyUsernameAction() {

		return new AbstractJKAction("getCopyUsernameAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 9097200540749722518L;

			@Override
			protected void doAction(ActionEvent e) {
				if (getSelectedAccount() != null
						&& getSelectedAccount() instanceof Account) {
					Toolkit toolkit = Toolkit.getDefaultToolkit();
					Clipboard clipboard = toolkit.getSystemClipboard();
					StringSelection strSel = new StringSelection(
							((Account) getSelectedAccount()).getUsername());
					clipboard.setContents(strSel, null);
				}

			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tabuto.jkeys.controllers.JKControllerInterface#getSaveSingleAccountAction
	 * ()
	 */
	@Override
	public AbstractJKAction getSaveSingleAccountAction() {

		return new AbstractJKAction("getSaveSingleAccountAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			@Override
			protected void doAction(ActionEvent e) {

				if (view.getTitleField().getText() == null
						|| view.getTitleField()
								.getText().equals("")) {
					JOptionPane.showMessageDialog(view.getMainJFrame(),
							"An Account requires Title!");
					return;
				}

				Account toAdd = new Account.Builder(view
						.getTitleField().getText())
						.username(
								view.getUsernameField()
										.getText())
						.password(
								String.valueOf(view.getPasswordField().getPassword()))
						.url(view.getUrlField()
								.getText())
						.notes(view.getNotesTextArea().getText()).build();

				// If selected is an empty account then add new
				// else edit change the current selected account with the new
				// edited one
				if (selected == null
						|| selected.equals(Account.NEW_EMPTY_ACCOUNT())) {
					root.add(toAdd);
				} else {
					root.remove(getSelectedAccount());
					root.add(toAdd);
					select(Account.NEW_EMPTY_ACCOUNT());
				}

				view.refresh();
			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.tabuto.jkeys.controllers.JKControllerInterface#getQuitJKey()
	 */
	@Override
	public AbstractJKAction getShowCreditAction() {
		return new AbstractJKAction("getShowCreditAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			@Override
			protected void doAction(ActionEvent e) {

				JOptionPane
						.showMessageDialog(view.getMainJFrame(), JKeysConstant.CREDITS_MESSAGE);
			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tabuto.jkeys.controllers.JKControllerInterface#getShowCreditAction()
	 */
	@Override
	public AbstractJKAction getExitAction() {

		return new AbstractJKAction("getExitAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			@Override
			protected void doAction(ActionEvent e) {

				view.getMainJFrame().dispose();
				System.exit(0);
			}
		};
	}

	/* (non-Javadoc)
	 * @see com.tabuto.jkeys.controllers.JKControllerInterface#setView(com.tabuto.jkeys.views.JKViewInterface)
	 */
	@Override
	public void setView(JKViewInterface view) {
		if (view == null)
			throw new NullPointerException("A not null MainWindow required");
		this.view = view;
		
	}

	/* (non-Javadoc)
	 * @see com.tabuto.jkeys.controllers.JKControllerInterface#getSaveRootAction()
	 */
	@Override
	public AbstractJKAction getSaveRootAction() {
		return new AbstractJKAction("getSaveRootAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			@Override
			protected void doAction(ActionEvent e) {

				try{
					
					File f;
		            JFileChooser fileChooser = new JFileChooser();
		            f = new File("JKPassword.dat");
		            fileChooser.setCurrentDirectory(f);
		            fileChooser.setSelectedFile(f);
		            int n = fileChooser.showSaveDialog(view.getMainJFrame());
		            if (n == JFileChooser.APPROVE_OPTION)
		            {              
		            	 FileOutputStream fos = null;
		                 ObjectOutputStream out = null;
		                 
		                 //Encrypt file before writing on disk
		               
		                 
		                 fos = new FileOutputStream(fileChooser.getSelectedFile().getAbsolutePath());
		                 out = new ObjectOutputStream(fos);
		                 
		                 //Convert an Object to an input Stream
		                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
		                 ObjectOutputStream oos = new ObjectOutputStream(baos);
		                 oos.writeObject(root);
		                 oos.flush();
		                 oos.close();
		                 InputStream is = new ByteArrayInputStream(baos.toByteArray());
		                 //Write into out the serialized crypted object
		                 JKUtils.encrypt(is, out, retrievePassword());
		                 
		                 //out.writeObject( root );
		                 
		                 out.close();
		                 
		                
		                 

		            }


		            

					
				}catch(Exception ex){
					ex.printStackTrace();
				}
			}
		};
	}

	/* (non-Javadoc)
	 * @see com.tabuto.jkeys.controllers.JKControllerInterface#getLoadRootAction()
	 */
	@Override
	public AbstractJKAction getLoadRootAction() {
		return new AbstractJKAction("getLoadRootAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			@Override
			protected void doAction(ActionEvent e) throws IOException, ClassNotFoundException  {

//				try {

					JFileChooser fileChooser = new JFileChooser();
					int n = fileChooser.showOpenDialog(view.getMainJFrame());
					if (n == JFileChooser.APPROVE_OPTION) {

						String path = fileChooser.getSelectedFile().getAbsolutePath();
						password = JKUtils.showInputPasswordDialog();
						FileInputStream fis = null;
						ObjectInputStream in = null;
						fis = new FileInputStream(path);
						in = new ObjectInputStream(fis);
						
						
						
						
						ByteArrayOutputStream obs = new ByteArrayOutputStream(1024);
						JKUtils.decrypt(in, obs, password);
						
						ObjectInputStream clearStream = new ObjectInputStream( new ByteArrayInputStream(obs.toByteArray()));
						
						AccountGroupList loaded = (AccountGroupList) clearStream.readObject();
						in.close();
						
						setRoot(loaded);
						view.refresh();
						
					}

//				} catch (Exception ex) {
//					throw new RuntimeException(ex);
//				}
			
			}
		};
	}

	/* (non-Javadoc)
	 * @see com.tabuto.jkeys.controllers.JKControllerInterface#getDeleteSingleAccountAction()
	 */
	@Override
	public AbstractJKAction getDeleteSingleAccountAction() {
		return new AbstractJKAction("getDeleteSingleAccountAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			@Override
			protected void doAction(ActionEvent e) {

					getRoot().remove(selected);
					selected = Account.NEW_EMPTY_ACCOUNT();
					view.refresh();
			}
		};
	}

	/* (non-Javadoc)
	 * @see com.tabuto.jkeys.controllers.JKControllerInterface#getSaveSelectedRootAction()
	 */
	@Override
	public AbstractJKAction getSaveSelectedRootAction() {
		return new AbstractJKAction("getSaveSelectedRootAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			@Override
			protected void doAction(ActionEvent e) throws IOException {


		            	 FileOutputStream fos = null;
		                 ObjectOutputStream out = null;
		                
		                 fos = new FileOutputStream(Preferences.getProperties("conf.data_file_path"));
		                 out = new ObjectOutputStream(fos);
		                 
		                 
		                 //Convert an Object to an input Stream
		                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
		                 ObjectOutputStream oos = new ObjectOutputStream(baos);
		                 oos.writeObject(root);
		                 oos.flush();
		                 oos.close();
		                 InputStream is = new ByteArrayInputStream(baos.toByteArray());
		                 //Write into out the serialized crypted object
		                 JKUtils.encrypt(is, out, retrievePassword());
		                 
		                 //out.writeObject( root );
		                 
		                 out.close();
		                 
		                 
		               //  out.writeObject( root );
		               //  out.close();
		                 
		                 
		          
//		                 //Encrypt Object Stream
//		                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
//		                 ByteArrayOutputStream cBaos = new ByteArrayOutputStream();
//		                 ObjectOutputStream oos = new ObjectOutputStream(baos);
//		                 oos.writeObject(root);
//		                 oos.flush();
//		                 oos.close();
//		                 InputStream is = new ByteArrayInputStream(out.toByteArray());
//		                 JKUtils.encrypt(is, cBaos, retrievePassword());
//		                 cBaos.reset();
//		                 ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(cBaos.toByteArray()));
//		                 root = (AccountGroupList)is.readObject();
//		                 out.writeObject( root );
//		                 out.close();

					
			}	
		};
		
	}

	/* (non-Javadoc)
	 * @see com.tabuto.jkeys.controllers.JKControllerInterface#getLoadSelectedRootAction()
	 */
	@Override
	public AbstractJKAction getLoadSelectedRootAction() {
		return new AbstractJKAction("getLoadSelectedRootAction") {

			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			@Override
			protected void doAction(ActionEvent e) throws IOException, ClassNotFoundException {



						String path = Preferences.getProperties("conf.data_file_path");
						FileInputStream fis = null;
						ObjectInputStream in = null;
						fis = new FileInputStream(path);
						in = new ObjectInputStream(fis);
			
						password = JKUtils.showInputPasswordDialog();
						
							
						
						
						
						
						ByteArrayOutputStream obs = new ByteArrayOutputStream(1024);
						try{
							JKUtils.decrypt(in, obs, password);
						} catch (java.io.StreamCorruptedException ex){
							JKUtils.showMessage("Wrong password!");
							//Redo action
							doAction(e);
						}
						
						ObjectInputStream clearStream = new ObjectInputStream( new ByteArrayInputStream(obs.toByteArray()));
						
						AccountGroupList loaded = (AccountGroupList) clearStream.readObject();
						in.close();
						
						setRoot(loaded);
						view.refresh();
						
						
						//ByteArrayOutputStream eBaos = new ByteArrayOutputStream();
						//ObjectOutputStream oos = new ObjectOutputStream(eBaos);
						//JKUtils.decrypt(in, oos, password);
						//eBaos.reset();
						//((ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(eBaos.toByteArray()));
						
						
//						AccountGroupList loaded = (AccountGroupList) in.readObject();
//						in.close();
//						
//						setRoot(loaded);
//						view.refresh();

				
			
			}
		};
	}

	/* (non-Javadoc)
	 * @see com.tabuto.jkeys.controllers.JKControllerInterface#retrievePassword()
	 */
	@Override
	public String retrievePassword() {
		if(!JKUtils.isEmptyOrNullString(password))
			return password;
		else {
			while(JKUtils.isEmptyOrNullString(password))
			password = JKUtils.showSetPasswordDialog();
		}
		
		
		return password;
		
	}

}
